#pragma once
#ifndef COMMAND_H
#define COMMAND_H

#include <iostream>
#include <string>
#include <regex>
#include <fstream>
#include "Database.h"

std::regex create_database_regex(R"(CREATE DATABASE (\w+);)", std::regex_constants::icase);
std::regex use_database_regex(R"(USE DATABASE (\w+);)", std::regex_constants::icase);
std::regex create_table_regex(R"(CREATE TABLE (\w+) \(([^)]+)\);)", std::regex_constants::icase);
std::regex insert_data_regex(R"(INSERT INTO (\w+) \(([^)]+)\) VALUES \(([^)]+)\);)", std::regex_constants::icase);
std::regex update_data_regex(R"(UPDATE (\w+) SET (.+) WHERE ([^;]+);)", std::regex_constants::icase);
std::regex delete_data_regex(R"(DELETE FROM (\w+) WHERE ([^;]+);)", std::regex_constants::icase);
std::regex select_data_regex(R"(SELECT (.+) FROM (\w+)(?: WHERE ([^;]+))?;)", std::regex_constants::icase);

Database* current_db = nullptr;

void use_database(const std::string& db_name) {
    std::string filename = db_name + ".txt";
    std::ifstream file(filename);
    if (file.good()) {
        file.close();
        if (current_db != nullptr) {
            delete current_db;
        }
        current_db = new Database(db_name);
        current_db->LoadFromFile(filename);
        std::cout << "Switched to database '" << db_name << "'." << std::endl;
    }
    else {
        std::cout << "Error: Database '" << db_name << "' does not exist." << std::endl;
    }
}

void execute_command(const std::string& command) {
    std::smatch matches;

    if (std::regex_match(command, matches, create_database_regex)) {
        std::string db_name = matches[1];
        Database db(db_name);
        db.SaveToFile(db_name + ".txt");
        std::cout << "Database '" << db_name << "' created successfully." << std::endl;
    }
    else if (std::regex_match(command, matches, use_database_regex)) {
        std::string db_name = matches[1];
        use_database(db_name);
    }
    else if (current_db != nullptr) {
        if (std::regex_match(command, matches, create_table_regex)) {
            std::string table_name = matches[1];
            std::string fields_str = matches[2];
            std::vector<std::string> field_names;
            std::vector<std::string> field_types;
            std::string field;
            std::istringstream iss(fields_str);
            while (std::getline(iss, field, ',')) {
                std::istringstream field_iss(field);
                std::string field_name, field_type;
                field_iss >> field_name >> field_type;
                field_names.push_back(field_name);
                field_types.push_back(field_type);
            }
            current_db->CreateTable(table_name, field_names, field_types);
        }
        else if (std::regex_match(command, matches, insert_data_regex)) {
            std::string table_name = matches[1];
            std::string fields_str = matches[2];
            std::string values_str = matches[3];
            std::vector<std::string> field_values;
            std::string value;
            std::istringstream iss(values_str);
            while (std::getline(iss, value, ',')) {
                if (!value.empty() && value.front() == '\'' && value.back() == '\'') {
                    value = value.substr(1, value.size() - 2);
                }
                field_values.push_back(value);
            }
            current_db->AddRowToTable(table_name, field_values);
        }
        else if (std::regex_match(command, matches, update_data_regex)) {
            std::string table_name = matches[1];
            std::string set_str = matches[2];
            std::string where_str = matches[3];
            std::vector<std::string> field_names;
            std::vector<std::string> field_values;
            std::string set_clause;
            std::istringstream set_iss(set_str);
            while (std::getline(set_iss, set_clause, ',')) {
                std::istringstream clause_iss(set_clause);
                std::string field_name, field_value;
                std::getline(clause_iss, field_name, '=');
                std::getline(clause_iss, field_value);
                if (!field_value.empty() && field_value.front() == '\'' && field_value.back() == '\'') {
                    field_value = field_value.substr(1, field_value.size() - 2);
                }
                field_names.push_back(field_name);
                field_values.push_back(field_value);
            }
            std::string where_field_name, where_field_value;
            std::istringstream where_iss(where_str);
            std::getline(where_iss, where_field_name, '=');
            std::getline(where_iss, where_field_value);
            if (!where_field_value.empty() && where_field_value.front() == '\'' && where_field_value.back() == '\'') {
                where_field_value = where_field_value.substr(1, where_field_value.size() - 2);
            }
            std::vector<int> row_indexes = current_db->FindIndexesFromTable(table_name, where_field_name, where_field_value);
            current_db->UpdateRowToTable(table_name, row_indexes, field_names, field_values);
        }
        else if (std::regex_match(command, matches, delete_data_regex)) {
            std::string table_name = matches[1];
            std::string where_str = matches[2];
            std::string where_field_name, where_field_value;
            std::istringstream where_iss(where_str);
            std::getline(where_iss, where_field_name, '=');
            std::getline(where_iss, where_field_value);
            if (!where_field_value.empty() && where_field_value.front() == '\'' && where_field_value.back() == '\'') {
                where_field_value = where_field_value.substr(1, where_field_value.size() - 2);
            }
            std::vector<int> row_indexes = current_db->FindIndexesFromTable(table_name, where_field_name, where_field_value);
            current_db->DeleteFromTable(table_name, row_indexes);
        }
        else if (std::regex_match(command, matches, select_data_regex)) {
            std::string fields_str = matches[1];
            std::string table_name = matches[2];
            std::string where_str = matches[3];
            std::vector<std::string> field_names;
            std::string field_name;
            std::istringstream fields_iss(fields_str);
            while (std::getline(fields_iss, field_name, ',')) {
                field_names.push_back(field_name);
            }
            if (where_str.empty()) {
                std::vector<int> all_indexes;
                int row_count = current_db->GetTable(table_name)->GetRowCount();
                for (int i = 0; i < row_count; ++i) {
                    all_indexes.push_back(i);
                }
                current_db->SelectFromTable(table_name, all_indexes, field_names);
            }
            else {
                std::string where_field_name, where_field_value;
                std::istringstream where_iss(where_str);
                std::getline(where_iss, where_field_name, '=');
                std::getline(where_iss, where_field_value);
                if (!where_field_value.empty() && where_field_value.front() == '\'' && where_field_value.back() == '\'') {
                    where_field_value = where_field_value.substr(1, where_field_value.size() - 2);
                }
                std::vector<int> row_indexes = current_db->FindIndexesFromTable(table_name, where_field_name, where_field_value);
                current_db->SelectFromTable(table_name, row_indexes, field_names);
            }
        }
        else {
            std::cout << "Invalid command." << std::endl;
        }
        current_db->SaveToFile(current_db->GetDatabaseName() + ".txt");
    }
    else {
        std::cout << "No database selected. Use 'USE DATABASE database_name;' to select a database." << std::endl;
    }
}

#endif // COMMAND_H